home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevpx.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  44.1 KB  |  1,586 lines

  1. /* Copyright (C) 1997, 2000 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevpx.c,v 1.4 2000/09/19 19:00:22 lpd Exp $ */
  20. /* H-P PCL XL driver */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "string_.h"
  24. #include "gx.h"
  25. #include "gserrors.h"
  26. #include "gsccolor.h"
  27. #include "gsdcolor.h"
  28. #include "gxcspace.h"        /* for color mapping for images */
  29. #include "gxdevice.h"
  30. #include "gxpath.h"
  31. #include "gdevvec.h"
  32. #include "strimpl.h"
  33. #include "srlx.h"
  34. #include "gdevpxat.h"
  35. #include "gdevpxen.h"
  36. #include "gdevpxop.h"
  37. #include "gdevpxut.h"
  38.  
  39. /* ---------------- Device definition ---------------- */
  40.  
  41. /* Define the default resolution. */
  42. #ifndef X_DPI
  43. #  define X_DPI 600
  44. #endif
  45. #ifndef Y_DPI
  46. #  define Y_DPI 600
  47. #endif
  48.  
  49. /* Structure definition */
  50. #define NUM_POINTS 40        /* must be >= 3 and <= 255 */
  51. typedef enum {
  52.     POINTS_NONE,
  53.     POINTS_LINES,
  54.     POINTS_CURVES
  55. } point_type_t;
  56. typedef struct gx_device_pclxl_s {
  57.     gx_device_vector_common;
  58.     /* Additional state information */
  59.     pxeMediaSize_t media_size;
  60.     gx_path_type_t fill_rule;    /* ...winding_number or ...even_odd  */
  61.     gx_path_type_t clip_rule;    /* ditto */
  62.     pxeColorSpace_t color_space;
  63.     struct pal_ {
  64.     int size;        /* # of bytes */
  65.     byte data[256 * 3];    /* up to 8-bit samples */
  66.     } palette;
  67.     struct pts_ {        /* buffer for accumulating path points */
  68.     gs_int_point current;    /* current point as of start of data */
  69.     point_type_t type;
  70.     int count;
  71.     gs_int_point data[NUM_POINTS];
  72.     } points;
  73.     struct ch_ {        /* cache for downloaded characters */
  74. #define MAX_CACHED_CHARS 400
  75. #define MAX_CHAR_DATA 500000
  76. #define MAX_CHAR_SIZE 5000
  77. #define CHAR_HASH_FACTOR 247
  78.     ushort table[MAX_CACHED_CHARS * 3 / 2];
  79.     struct cd_ {
  80.         gs_id id;        /* key */
  81.         uint size;
  82.     } data[MAX_CACHED_CHARS];
  83.     int next_in;        /* next data element to fill in */
  84.     int next_out;        /* next data element to discard */
  85.     int count;        /* of occupied data elements */
  86.     ulong used;
  87.     } chars;
  88.     bool font_set;
  89. } gx_device_pclxl;
  90.  
  91. gs_public_st_suffix_add0_final(st_device_pclxl, gx_device_pclxl,
  92.                    "gx_device_pclxl",
  93.                    device_pclxl_enum_ptrs, device_pclxl_reloc_ptrs,
  94.                    gx_device_finalize, st_device_vector);
  95.  
  96. #define pclxl_device_body(dname, depth)\
  97.   std_device_dci_type_body(gx_device_pclxl, 0, dname, &st_device_pclxl,\
  98.                DEFAULT_WIDTH_10THS * X_DPI / 10,\
  99.                DEFAULT_HEIGHT_10THS * Y_DPI / 10,\
  100.                X_DPI, Y_DPI,\
  101.                (depth > 8 ? 3 : 1), depth,\
  102.                (depth > 1 ? 255 : 1), (depth > 8 ? 255 : 0),\
  103.                (depth > 1 ? 256 : 2), (depth > 8 ? 256 : 1))
  104.  
  105. /* Driver procedures */
  106. private dev_proc_open_device(pclxl_open_device);
  107. private dev_proc_output_page(pclxl_output_page);
  108. private dev_proc_close_device(pclxl_close_device);
  109. private dev_proc_copy_mono(pclxl_copy_mono);
  110. private dev_proc_copy_color(pclxl_copy_color);
  111. private dev_proc_fill_mask(pclxl_fill_mask);
  112.  
  113. /*private dev_proc_draw_thin_line(pclxl_draw_thin_line); */
  114. private dev_proc_begin_image(pclxl_begin_image);
  115. private dev_proc_strip_copy_rop(pclxl_strip_copy_rop);
  116.  
  117. #define pclxl_device_procs(map_rgb_color, map_color_rgb)\
  118. {\
  119.     pclxl_open_device,\
  120.     NULL,            /* get_initial_matrix */\
  121.     NULL,            /* sync_output */\
  122.     pclxl_output_page,\
  123.     pclxl_close_device,\
  124.     map_rgb_color,        /* differs */\
  125.     map_color_rgb,        /* differs */\
  126.     gdev_vector_fill_rectangle,\
  127.     NULL,            /* tile_rectangle */\
  128.     pclxl_copy_mono,\
  129.     pclxl_copy_color,\
  130.     NULL,            /* draw_line */\
  131.     NULL,            /* get_bits */\
  132.     gdev_vector_get_params,\
  133.     gdev_vector_put_params,\
  134.     NULL,            /* map_cmyk_color */\
  135.     NULL,            /* get_xfont_procs */\
  136.     NULL,            /* get_xfont_device */\
  137.     NULL,            /* map_rgb_alpha_color */\
  138.     gx_page_device_get_page_device,\
  139.     NULL,            /* get_alpha_bits */\
  140.     NULL,            /* copy_alpha */\
  141.     NULL,            /* get_band */\
  142.     NULL,            /* copy_rop */\
  143.     gdev_vector_fill_path,\
  144.     gdev_vector_stroke_path,\
  145.     pclxl_fill_mask,\
  146.     gdev_vector_fill_trapezoid,\
  147.     gdev_vector_fill_parallelogram,\
  148.     gdev_vector_fill_triangle,\
  149.     NULL /****** WRONG ******/,    /* draw_thin_line */\
  150.     pclxl_begin_image,\
  151.     NULL,            /* image_data */\
  152.     NULL,            /* end_image */\
  153.     NULL,            /* strip_tile_rectangle */\
  154.     pclxl_strip_copy_rop\
  155. }
  156.  
  157. const gx_device_pclxl gs_pxlmono_device = {
  158.     pclxl_device_body("pxlmono", 8),
  159.     pclxl_device_procs(gx_default_gray_map_rgb_color, gx_default_gray_map_color_rgb)
  160. };
  161.  
  162. const gx_device_pclxl gs_pxlcolor_device = {
  163.     pclxl_device_body("pxlcolor", 24),
  164.     pclxl_device_procs(gx_default_rgb_map_rgb_color, gx_default_rgb_map_color_rgb)
  165. };
  166.  
  167. /* ---------------- Other utilities ---------------- */
  168.  
  169. inline private stream *
  170. pclxl_stream(gx_device_pclxl *xdev)
  171. {
  172.     return gdev_vector_stream((gx_device_vector *)xdev);
  173. }
  174.  
  175. /* Initialize for a page. */
  176. private void
  177. pclxl_page_init(gx_device_pclxl * xdev)
  178. {
  179.     gdev_vector_init((gx_device_vector *)xdev);
  180.     xdev->in_page = false;
  181.     xdev->fill_rule = gx_path_type_winding_number;
  182.     xdev->clip_rule = gx_path_type_winding_number;
  183.     xdev->color_space = eNoColorSpace;
  184.     xdev->palette.size = 0;
  185.     xdev->font_set = false;
  186. }
  187.  
  188. /* Test whether a RGB color is actually a gray shade. */
  189. #define RGB_IS_GRAY(ci) ((ci) >> 8 == ((ci) & 0xffff))
  190.  
  191. /* Set the color space and (optionally) palette. */
  192. private void
  193. pclxl_set_color_space(gx_device_pclxl * xdev, pxeColorSpace_t color_space)
  194. {
  195.     if (xdev->color_space != color_space) {
  196.     stream *s = pclxl_stream(xdev);
  197.  
  198.     px_put_ub(s, color_space);
  199.     px_put_ac(s, pxaColorSpace, pxtSetColorSpace);
  200.     xdev->color_space = color_space;
  201.     }
  202. }
  203. private void
  204. pclxl_set_color_palette(gx_device_pclxl * xdev, pxeColorSpace_t color_space,
  205.             const byte * palette, uint palette_size)
  206. {
  207.     if (xdev->color_space != color_space ||
  208.     xdev->palette.size != palette_size ||
  209.     memcmp(xdev->palette.data, palette, palette_size)
  210.     ) {
  211.     stream *s = pclxl_stream(xdev);
  212.     static const byte csp_[] = {
  213.         DA(pxaColorSpace),
  214.         DUB(e8Bit), DA(pxaPaletteDepth),
  215.         pxt_ubyte_array
  216.     };
  217.  
  218.     px_put_ub(s, color_space);
  219.     PX_PUT_LIT(s, csp_);
  220.     px_put_u(s, palette_size);
  221.     px_put_bytes(s, palette, palette_size);
  222.     px_put_ac(s, pxaPaletteData, pxtSetColorSpace);
  223.     xdev->color_space = color_space;
  224.     xdev->palette.size = palette_size;
  225.     memcpy(xdev->palette.data, palette, palette_size);
  226.     }
  227. }
  228.  
  229. /* Set a drawing RGB color. */
  230. private int
  231. pclxl_set_color(gx_device_pclxl * xdev, const gx_drawing_color * pdc,
  232.         px_attribute_t null_source, px_tag_t op)
  233. {
  234.     stream *s = pclxl_stream(xdev);
  235.  
  236.     if (gx_dc_is_pure(pdc)) {
  237.     gx_color_index color = gx_dc_pure_color(pdc);
  238.  
  239.     if (xdev->color_info.num_components == 1 || RGB_IS_GRAY(color)) {
  240.         pclxl_set_color_space(xdev, eGray);
  241.         px_put_uba(s, (byte) color, pxaGrayLevel);
  242.     } else {
  243.         pclxl_set_color_space(xdev, eRGB);
  244.         spputc(s, pxt_ubyte_array);
  245.         px_put_ub(s, 3);
  246.         spputc(s, (byte) (color >> 16));
  247.         spputc(s, (byte) (color >> 8));
  248.         spputc(s, (byte) color);
  249.         px_put_a(s, pxaRGBColor);
  250.     }
  251.     } else if (gx_dc_is_null(pdc))
  252.     px_put_uba(s, 0, null_source);
  253.     else
  254.     return_error(gs_error_rangecheck);
  255.     spputc(s, op);
  256.     return 0;
  257. }
  258.  
  259. /* Test whether we can handle a given color space in an image. */
  260. private bool
  261. pclxl_can_handle_color_space(const gs_color_space * pcs)
  262. {
  263.     gs_color_space_index index = gs_color_space_get_index(pcs);
  264.  
  265.     if (index == gs_color_space_index_Indexed) {
  266.     if (pcs->params.indexed.use_proc)
  267.         return false;
  268.     index =
  269.         gs_color_space_get_index(gs_color_space_indexed_base_space(pcs));
  270.     }
  271.     return !(index == gs_color_space_index_Separation ||
  272.          index == gs_color_space_index_Pattern);
  273. }
  274.  
  275. /* Set brush, pen, and mode for painting a path. */
  276. private void
  277. pclxl_set_paints(gx_device_pclxl * xdev, gx_path_type_t type)
  278. {
  279.     stream *s = pclxl_stream(xdev);
  280.     gx_path_type_t rule = type & gx_path_type_rule;
  281.  
  282.     if (!(type & gx_path_type_fill) &&
  283.     !gx_dc_is_null(&xdev->fill_color)
  284.     ) {
  285.     static const byte nac_[] = {
  286.         DUB(0), DA(pxaNullBrush), pxtSetBrushSource
  287.     };
  288.  
  289.     PX_PUT_LIT(s, nac_);
  290.     color_set_null(&xdev->fill_color);
  291.     if (rule != xdev->fill_rule) {
  292.         px_put_ub(s, (rule == gx_path_type_even_odd ? eEvenOdd :
  293.                eNonZeroWinding));
  294.         px_put_ac(s, pxaFillMode, pxtSetFillMode);
  295.         xdev->fill_rule = rule;
  296.     }
  297.     }
  298.     if (!(type & gx_path_type_stroke) &&
  299.     !gx_dc_is_null(&xdev->stroke_color)
  300.     ) {
  301.     static const byte nac_[] = {
  302.         DUB(0), DA(pxaNullPen), pxtSetPenSource
  303.     };
  304.  
  305.     PX_PUT_LIT(s, nac_);
  306.     color_set_null(&xdev->stroke_color);
  307.     }
  308. }
  309.  
  310. /* Set the cursor. */
  311. private int
  312. pclxl_set_cursor(gx_device_pclxl * xdev, int x, int y)
  313. {
  314.     stream *s = pclxl_stream(xdev);
  315.  
  316.     px_put_ssp(s, x, y);
  317.     px_put_ac(s, pxaPoint, pxtSetCursor);
  318.     return 0;
  319. }
  320.  
  321. /* ------ Paths ------ */
  322.  
  323. /* Flush any buffered path points. */
  324. private void
  325. px_put_np(stream * s, int count, pxeDataType_t dtype)
  326. {
  327.     px_put_uba(s, count, pxaNumberOfPoints);
  328.     px_put_uba(s, dtype, pxaPointType);
  329. }
  330. private int
  331. pclxl_flush_points(gx_device_pclxl * xdev)
  332. {
  333.     int count = xdev->points.count;
  334.  
  335.     if (count) {
  336.     stream *s = pclxl_stream(xdev);
  337.     px_tag_t op;
  338.     int x = xdev->points.current.x, y = xdev->points.current.y;
  339.     int uor = 0, sor = 0;
  340.     pxeDataType_t data_type;
  341.     int i, di;
  342.     byte diffs[NUM_POINTS * 2];
  343.  
  344.     /*
  345.      * Writing N lines using a point list requires 11 + 4*N or 11 +
  346.      * 2*N bytes, as opposed to 8*N bytes using separate commands;
  347.      * writing N curves requires 11 + 12*N or 11 + 6*N bytes
  348.      * vs. 22*N.  So it's always shorter to write curves with a
  349.      * list (except for N = 1 with full-size coordinates, but since
  350.      * the difference is only 1 byte, we don't bother to ever use
  351.      * the non-list form), but lines are shorter only if N >= 3
  352.      * (again, with a 1-byte difference if N = 2 and byte
  353.      * coordinates).
  354.      */
  355.     switch (xdev->points.type) {
  356.         case POINTS_NONE:
  357.         return 0;
  358.         case POINTS_LINES:
  359.         op = pxtLinePath;
  360.         if (count < 3) {
  361.             for (i = 0; i < count; ++i) {
  362.             px_put_ssp(s, xdev->points.data[i].x,
  363.                 xdev->points.data[i].y);
  364.             px_put_a(s, pxaEndPoint);
  365.             spputc(s, op);
  366.             }
  367.             goto zap;
  368.         }
  369.         /* See if we can use byte values. */
  370.         for (i = di = 0; i < count; ++i, di += 2) {
  371.             int dx = xdev->points.data[i].x - x;
  372.             int dy = xdev->points.data[i].y - y;
  373.  
  374.             diffs[di] = (byte) dx;
  375.             diffs[di + 1] = (byte) dy;
  376.             uor |= dx | dy;
  377.             sor |= (dx + 0x80) | (dy + 0x80);
  378.             x += dx, y += dy;
  379.         }
  380.         if (!(uor & ~0xff))
  381.             data_type = eUByte;
  382.         else if (!(sor & ~0xff))
  383.             data_type = eSByte;
  384.         else
  385.             break;
  386.         op = pxtLineRelPath;
  387.         /* Use byte values. */
  388.           useb:px_put_np(s, count, data_type);
  389.         spputc(s, op);
  390.         px_put_data_length(s, count * 2);    /* 2 bytes per point */
  391.         px_put_bytes(s, diffs, count * 2);
  392.         goto zap;
  393.         case POINTS_CURVES:
  394.         op = pxtBezierPath;
  395.         /* See if we can use byte values. */
  396.         for (i = di = 0; i < count; i += 3, di += 6) {
  397.             int dx1 = xdev->points.data[i].x - x;
  398.             int dy1 = xdev->points.data[i].y - y;
  399.             int dx2 = xdev->points.data[i + 1].x - x;
  400.             int dy2 = xdev->points.data[i + 1].y - y;
  401.             int dx = xdev->points.data[i + 2].x - x;
  402.             int dy = xdev->points.data[i + 2].y - y;
  403.  
  404.             diffs[di] = (byte) dx1;
  405.             diffs[di + 1] = (byte) dy1;
  406.             diffs[di + 2] = (byte) dx2;
  407.             diffs[di + 3] = (byte) dy2;
  408.             diffs[di + 4] = (byte) dx;
  409.             diffs[di + 5] = (byte) dy;
  410.             uor |= dx1 | dy1 | dx2 | dy2 | dx | dy;
  411.             sor |= (dx1 + 0x80) | (dy1 + 0x80) |
  412.             (dx2 + 0x80) | (dy2 + 0x80) |
  413.             (dx + 0x80) | (dy + 0x80);
  414.             x += dx, y += dy;
  415.         }
  416.         if (!(uor & ~0xff))
  417.             data_type = eUByte;
  418.         else if (!(sor & ~0xff))
  419.             data_type = eSByte;
  420.         else
  421.             break;
  422.         op = pxtBezierRelPath;
  423.         goto useb;
  424.         default:        /* can't happen */
  425.         return_error(gs_error_unknownerror);
  426.     }
  427.     px_put_np(s, count, eSInt16);
  428.     spputc(s, op);
  429.     px_put_data_length(s, count * 4);    /* 2 UInt16s per point */
  430.     for (i = 0; i < count; ++i) {
  431.         px_put_s(s, xdev->points.data[i].x);
  432.         px_put_s(s, xdev->points.data[i].y);
  433.     }
  434.       zap:xdev->points.type = POINTS_NONE;
  435.     xdev->points.count = 0;
  436.     }
  437.     return 0;
  438. }
  439.  
  440. /* ------ Images ------ */
  441.  
  442. private image_enum_proc_plane_data(pclxl_image_plane_data);
  443. private image_enum_proc_end_image(pclxl_image_end_image);
  444. private const gx_image_enum_procs_t pclxl_image_enum_procs = {
  445.     pclxl_image_plane_data, pclxl_image_end_image
  446. };
  447.  
  448. /* Begin an image. */
  449. private void
  450. pclxl_write_begin_image(gx_device_pclxl * xdev, uint width, uint height,
  451.             uint dest_width, uint dest_height)
  452. {
  453.     stream *s = pclxl_stream(xdev);
  454.  
  455.     px_put_usa(s, width, pxaSourceWidth);
  456.     px_put_usa(s, height, pxaSourceHeight);
  457.     px_put_usp(s, dest_width, dest_height);
  458.     px_put_ac(s, pxaDestinationSize, pxtBeginImage);
  459. }
  460.  
  461. /* Write rows of an image. */
  462. /****** IGNORES data_bit ******/
  463. private void
  464. pclxl_write_image_data(gx_device_pclxl * xdev, const byte * data, int data_bit,
  465.                uint raster, uint width_bits, int y, int height)
  466. {
  467.     stream *s = pclxl_stream(xdev);
  468.     uint width_bytes = (width_bits + 7) >> 3;
  469.     uint num_bytes = ROUND_UP(width_bytes, 4) * height;
  470.     bool compress = num_bytes >= 8;
  471.     int i;
  472.  
  473.     px_put_usa(s, y, pxaStartLine);
  474.     px_put_usa(s, height, pxaBlockHeight);
  475.     if (compress) {
  476.     stream_RLE_state rlstate;
  477.     stream_cursor_write w;
  478.     stream_cursor_read r;
  479.  
  480.     /*
  481.      * H-P printers require that all the data for an operator be
  482.      * contained in a single data block.  Thus, we must allocate a
  483.      * temporary buffer for the compressed data.  Currently we don't go
  484.      * to the trouble of doing two passes if we can't allocate a buffer
  485.      * large enough for the entire transfer.
  486.      */
  487.     byte *buf = gs_alloc_bytes(xdev->v_memory, num_bytes,
  488.                    "pclxl_write_image_data");
  489.  
  490.     if (buf == 0)
  491.         goto nc;
  492.     s_RLE_set_defaults_inline(&rlstate);
  493.     rlstate.EndOfData = false;
  494.     s_RLE_init_inline(&rlstate);
  495.     w.ptr = buf - 1;
  496.     w.limit = w.ptr + num_bytes;
  497.     /*
  498.      * If we ever overrun the buffer, it means that the compressed
  499.      * data was larger than the uncompressed.  If this happens,
  500.      * write the data uncompressed.
  501.      */
  502.     for (i = 0; i < height; ++i) {
  503.         r.ptr = data + i * raster - 1;
  504.         r.limit = r.ptr + width_bytes;
  505.         if ((*s_RLE_template.process)
  506.         ((stream_state *) & rlstate, &r, &w, false) != 0 ||
  507.         r.ptr != r.limit
  508.         )
  509.         goto ncfree;
  510.         r.ptr = (const byte *)"\000\000\000\000\000";
  511.         r.limit = r.ptr + (-width_bytes & 3);
  512.         if ((*s_RLE_template.process)
  513.         ((stream_state *) & rlstate, &r, &w, false) != 0 ||
  514.         r.ptr != r.limit
  515.         )
  516.         goto ncfree;
  517.     }
  518.     r.ptr = r.limit;
  519.     if ((*s_RLE_template.process)
  520.         ((stream_state *) & rlstate, &r, &w, true) != 0
  521.         )
  522.         goto ncfree;
  523.     {
  524.         uint count = w.ptr + 1 - buf;
  525.  
  526.         px_put_ub(s, eRLECompression);
  527.         px_put_ac(s, pxaCompressMode, pxtReadImage);
  528.         px_put_data_length(s, count);
  529.         px_put_bytes(s, buf, count);
  530.     }
  531.     gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
  532.     return;
  533.       ncfree:gs_free_object(xdev->v_memory, buf, "pclxl_write_image_data");
  534.     }
  535.  nc:
  536.     /* Write the data uncompressed. */
  537.     px_put_ub(s, eNoCompression);
  538.     px_put_ac(s, pxaCompressMode, pxtReadImage);
  539.     px_put_data_length(s, num_bytes);
  540.     for (i = 0; i < height; ++i) {
  541.     px_put_bytes(s, data + i * raster, width_bytes);
  542.     px_put_bytes(s, (const byte *)"\000\000\000\000", -width_bytes & 3);
  543.     }
  544. }
  545.  
  546. /* End an image. */
  547. private void
  548. pclxl_write_end_image(gx_device_pclxl * xdev)
  549. {
  550.     spputc(xdev->strm, pxtEndImage);
  551. }
  552.  
  553. /* ------ Fonts ------ */
  554.  
  555. /* Write a string (single- or double-byte). */
  556. private void
  557. px_put_string(stream * s, const byte * data, uint len, bool wide)
  558. {
  559.     if (wide) {
  560.     spputc(s, pxt_uint16_array);
  561.     px_put_u(s, len);
  562.     px_put_bytes(s, data, len * 2);
  563.     } else {
  564.     spputc(s, pxt_ubyte_array);
  565.     px_put_u(s, len);
  566.     px_put_bytes(s, data, len);
  567.     }
  568. }
  569.  
  570. /* Write a 16-bit big-endian value. */
  571. private void
  572. px_put_us_be(stream * s, uint i)
  573. {
  574.     spputc(s, (byte) (i >> 8));
  575.     spputc(s, (byte) i);
  576. }
  577.  
  578. /* Define a bitmap font.  The client must call px_put_string */
  579. /* with the font name immediately before calling this procedure. */
  580. private void
  581. pclxl_define_bitmap_font(gx_device_pclxl * xdev)
  582. {
  583.     stream *s = pclxl_stream(xdev);
  584.     static const byte bfh_[] = {
  585.     DA(pxaFontName), DUB(0), DA(pxaFontFormat),
  586.     pxtBeginFontHeader,
  587.     DUS(8 + 6 + 4 + 6), DA(pxaFontHeaderLength),
  588.     pxtReadFontHeader,
  589.     pxt_dataLengthByte, 8 + 6 + 4 + 6,
  590.     0, 0, 0, 0,
  591.     254, 0, (MAX_CACHED_CHARS + 255) >> 8, 0,
  592.     'B', 'R', 0, 0, 0, 4
  593.     };
  594.     static const byte efh_[] = {
  595.     0xff, 0xff, 0, 0, 0, 0,
  596.     pxtEndFontHeader
  597.     };
  598.  
  599.     PX_PUT_LIT(s, bfh_);
  600.     px_put_us_be(s, (uint) (xdev->HWResolution[0] + 0.5));
  601.     px_put_us_be(s, (uint) (xdev->HWResolution[1] + 0.5));
  602.     PX_PUT_LIT(s, efh_);
  603. }
  604.  
  605. /* Set the font.  The client must call px_put_string */
  606. /* with the font name immediately before calling this procedure. */
  607. private void
  608. pclxl_set_font(gx_device_pclxl * xdev)
  609. {
  610.     stream *s = pclxl_stream(xdev);
  611.     static const byte sf_[] = {
  612.     DA(pxaFontName), DUB(1), DA(pxaCharSize), DUS(0), DA(pxaSymbolSet),
  613.     pxtSetFont
  614.     };
  615.  
  616.     PX_PUT_LIT(s, sf_);
  617. }
  618.  
  619. /* Define a character in a bitmap font.  The client must call px_put_string */
  620. /* with the font name immediately before calling this procedure. */
  621. private void
  622. pclxl_define_bitmap_char(gx_device_pclxl * xdev, uint ccode,
  623.            const byte * data, uint raster, uint width_bits, uint height)
  624. {
  625.     stream *s = pclxl_stream(xdev);
  626.     uint width_bytes = (width_bits + 7) >> 3;
  627.     uint size = 10 + width_bytes * height;
  628.     uint i;
  629.  
  630.     px_put_ac(s, pxaFontName, pxtBeginChar);
  631.     px_put_u(s, ccode);
  632.     px_put_a(s, pxaCharCode);
  633.     if (size > 0xffff) {
  634.     spputc(s, pxt_uint32);
  635.     px_put_l(s, (ulong) size);
  636.     } else
  637.     px_put_us(s, size);
  638.     px_put_ac(s, pxaCharDataSize, pxtReadChar);
  639.     px_put_data_length(s, size);
  640.     px_put_bytes(s, (const byte *)"\000\000\000\000\000\000", 6);
  641.     px_put_us_be(s, width_bits);
  642.     px_put_us_be(s, height);
  643.     for (i = 0; i < height; ++i)
  644.     px_put_bytes(s, data + i * raster, width_bytes);
  645.     spputc(s, pxtEndChar);
  646. }
  647.  
  648. /* Write the name of the only font we define. */
  649. private void
  650. pclxl_write_font_name(gx_device_pclxl * xdev)
  651. {
  652.     stream *s = pclxl_stream(xdev);
  653.  
  654.     px_put_string(s, (const byte *)"@", 1, false);
  655. }
  656.  
  657. /* Look up a bitmap id, return the index in the character table. */
  658. /* If the id is missing, return an index for inserting. */
  659. private int
  660. pclxl_char_index(gx_device_pclxl * xdev, gs_id id)
  661. {
  662.     int i, i_empty = -1;
  663.     uint ccode;
  664.  
  665.     for (i = (id * CHAR_HASH_FACTOR) % countof(xdev->chars.table);;
  666.      i = (i == 0 ? countof(xdev->chars.table) : i) - 1
  667.     ) {
  668.     ccode = xdev->chars.table[i];
  669.     if (ccode == 0)
  670.         return (i_empty >= 0 ? i_empty : i);
  671.     else if (ccode == 1) {
  672.         if (i_empty < 0)
  673.         i_empty = i;
  674.         else if (i == i_empty)    /* full table */
  675.         return i;
  676.     } else if (xdev->chars.data[ccode].id == id)
  677.         return i;
  678.     }
  679. }
  680.  
  681. /* Remove the character table entry at a given index. */
  682. private void
  683. pclxl_remove_char(gx_device_pclxl * xdev, int index)
  684. {
  685.     uint ccode = xdev->chars.table[index];
  686.     int i;
  687.  
  688.     if (ccode < 2)
  689.     return;
  690.     xdev->chars.count--;
  691.     xdev->chars.used -= xdev->chars.data[ccode].size;
  692.     xdev->chars.table[index] = 1;    /* mark as deleted */
  693.     i = (index == 0 ? countof(xdev->chars.table) : index) - 1;
  694.     if (xdev->chars.table[i] == 0) {
  695.     /* The next slot in probe order is empty. */
  696.     /* Mark this slot and any deleted predecessors as empty. */
  697.     for (i = index; xdev->chars.table[i] == 1;
  698.          i = (i == countof(xdev->chars.table) - 1 ? 0 : i + 1)
  699.         )
  700.         xdev->chars.table[i] = 0;
  701.     }
  702. }
  703.  
  704. /* Write a bitmap as a text character if possible. */
  705. /* The caller must set the color, cursor, and RasterOp. */
  706. /* We know id != gs_no_id. */
  707. private int
  708. pclxl_copy_text_char(gx_device_pclxl * xdev, const byte * data,
  709.              int raster, gx_bitmap_id id, int w, int h)
  710. {
  711.     uint width_bytes = (w + 7) >> 3;
  712.     uint size = width_bytes * h;
  713.     int index;
  714.     uint ccode;
  715.     stream *s = pclxl_stream(xdev);
  716.  
  717.     if (size > MAX_CHAR_SIZE)
  718.     return -1;
  719.     index = pclxl_char_index(xdev, id);
  720.     if ((ccode = xdev->chars.table[index]) < 2) {
  721.     /* Enter the character in the table. */
  722.     while (xdev->chars.used + size > MAX_CHAR_DATA ||
  723.            xdev->chars.count >= MAX_CACHED_CHARS - 2
  724.         ) {
  725.         ccode = xdev->chars.next_out;
  726.         index = pclxl_char_index(xdev, xdev->chars.data[ccode].id);
  727.         pclxl_remove_char(xdev, index);
  728.         xdev->chars.next_out =
  729.         (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
  730.     }
  731.     index = pclxl_char_index(xdev, id);
  732.     ccode = xdev->chars.next_in;
  733.     xdev->chars.data[ccode].id = id;
  734.     xdev->chars.data[ccode].size = size;
  735.     xdev->chars.table[index] = ccode;
  736.     xdev->chars.next_in =
  737.         (ccode == MAX_CACHED_CHARS - 1 ? 2 : ccode + 1);
  738.     if (!xdev->chars.count++) {
  739.         /* This is the very first character. */
  740.         pclxl_write_font_name(xdev);
  741.         pclxl_define_bitmap_font(xdev);
  742.     }
  743.     xdev->chars.used += size;
  744.     pclxl_write_font_name(xdev);
  745.     pclxl_define_bitmap_char(xdev, ccode, data, raster, w, h);
  746.     }
  747.     if (!xdev->font_set) {
  748.     pclxl_write_font_name(xdev);
  749.     pclxl_set_font(xdev);
  750.     xdev->font_set = true;
  751.     } {
  752.     byte cc_bytes[2];
  753.  
  754.     cc_bytes[0] = (byte) ccode;
  755.     cc_bytes[1] = ccode >> 8;
  756.     px_put_string(s, cc_bytes, 1, cc_bytes[1] != 0);
  757.     }
  758.     px_put_ac(s, pxaTextData, pxtText);
  759.     return 0;
  760. }
  761.  
  762. /* ---------------- Vector implementation procedures ---------------- */
  763.  
  764. private int
  765. pclxl_beginpage(gx_device_vector * vdev)
  766. {
  767.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  768.     /*
  769.      * We can't use gdev_vector_stream here, because this may be called
  770.      * from there before in_page is set.
  771.      */
  772.     stream *s = vdev->strm;
  773.  
  774.     px_write_page_header(s, (const gx_device *)vdev);
  775.     px_write_select_media(s, (const gx_device *)vdev, &xdev->media_size);
  776.     spputc(s, pxtBeginPage);
  777.     return 0;
  778. }
  779.  
  780. private int
  781. pclxl_setlinewidth(gx_device_vector * vdev, floatp width)
  782. {
  783.     stream *s = gdev_vector_stream(vdev);
  784.  
  785.     px_put_us(s, (uint) width);
  786.     px_put_ac(s, pxaPenWidth, pxtSetPenWidth);
  787.     return 0;
  788. }
  789.  
  790. private int
  791. pclxl_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
  792. {
  793.     stream *s = gdev_vector_stream(vdev);
  794.  
  795.     /* The PCL XL cap styles just happen to be identical to PostScript. */
  796.     px_put_ub(s, (byte) cap);
  797.     px_put_ac(s, pxaLineCapStyle, pxtSetLineCap);
  798.     return 0;
  799. }
  800.  
  801. private int
  802. pclxl_setlinejoin(gx_device_vector * vdev, gs_line_join join)
  803. {
  804.     stream *s = gdev_vector_stream(vdev);
  805.  
  806.     /* The PCL XL join styles just happen to be identical to PostScript. */
  807.     px_put_ub(s, (byte) join);
  808.     px_put_ac(s, pxaLineJoinStyle, pxtSetLineJoin);
  809.     return 0;
  810. }
  811.  
  812. private int
  813. pclxl_setmiterlimit(gx_device_vector * vdev, floatp limit)
  814. {
  815.     stream *s = gdev_vector_stream(vdev);
  816.     /*
  817.      * Amazingly enough, the PCL XL specification doesn't allow real
  818.      * numbers for the miter limit.
  819.      */
  820.     int i_limit = (int)(limit + 0.5);
  821.  
  822.     px_put_u(s, max(i_limit, 1));
  823.     px_put_ac(s, pxaMiterLength, pxtSetMiterLimit);
  824.     return 0;
  825. }
  826.  
  827. private int
  828. pclxl_setdash(gx_device_vector * vdev, const float *pattern, uint count,
  829.           floatp offset)
  830. {
  831.     stream *s = gdev_vector_stream(vdev);
  832.  
  833.     if (count == 0) {
  834.     static const byte nac_[] = {
  835.         DUB(0), DA(pxaSolidLine)
  836.     };
  837.  
  838.     PX_PUT_LIT(s, nac_);
  839.     } else if (count > 255)
  840.     return_error(gs_error_limitcheck);
  841.     else {
  842.     uint i;
  843.  
  844.     /*
  845.      * Astoundingly, PCL XL doesn't allow real numbers here.
  846.      * Do the best we can.
  847.      */
  848.     spputc(s, pxt_uint16_array);
  849.     px_put_ub(s, count);
  850.     for (i = 0; i < count; ++i)
  851.         px_put_s(s, (uint)pattern[i]);
  852.     px_put_a(s, pxaLineDashStyle);
  853.     if (offset != 0) {
  854.         px_put_rl(s, offset);
  855.         px_put_a(s, pxaDashOffset);
  856.     }
  857.     }
  858.     spputc(s, pxtSetLineDash);
  859.     return 0;
  860. }
  861.  
  862. private int
  863. pclxl_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
  864.            gs_logical_operation_t diff)
  865. {
  866.     stream *s = gdev_vector_stream(vdev);
  867.  
  868.     if (diff & lop_S_transparent) {
  869.     px_put_ub(s, (lop & lop_S_transparent ? 1 : 0));
  870.     px_put_ac(s, pxaTxMode, pxtSetSourceTxMode);
  871.     }
  872.     if (diff & lop_T_transparent) {
  873.     px_put_ub(s, (lop & lop_T_transparent ? 1 : 0));
  874.     px_put_ac(s, pxaTxMode, pxtSetPaintTxMode);
  875.     }
  876.     if (lop_rop(diff)) {
  877.     px_put_ub(s, lop_rop(lop));
  878.     px_put_ac(s, pxaROP3, pxtSetROP);
  879.     }
  880.     return 0;
  881. }
  882.  
  883. private int
  884. pclxl_setfillcolor(gx_device_vector * vdev, const gx_drawing_color * pdc)
  885. {
  886.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  887.  
  888.     return pclxl_set_color(xdev, pdc, pxaNullBrush, pxtSetBrushSource);
  889. }
  890.  
  891. private int
  892. pclxl_setstrokecolor(gx_device_vector * vdev, const gx_drawing_color * pdc)
  893. {
  894.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  895.  
  896.     return pclxl_set_color(xdev, pdc, pxaNullPen, pxtSetPenSource);
  897. }
  898.  
  899. private int
  900. pclxl_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1,
  901.          fixed y1, gx_path_type_t type)
  902. {
  903.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  904.     stream *s = gdev_vector_stream(vdev);
  905.  
  906.     /* Check for out-of-range points. */
  907. #define OUT_OF_RANGE(v) (v < 0 || v >= int2fixed(0x10000))
  908.     if (OUT_OF_RANGE(x0) || OUT_OF_RANGE(y0) ||
  909.     OUT_OF_RANGE(x1) || OUT_OF_RANGE(y1)
  910.     )
  911.     return_error(gs_error_rangecheck);
  912. #undef OUT_OF_RANGE
  913.     if (type & (gx_path_type_fill | gx_path_type_stroke)) {
  914.     pclxl_set_paints(xdev, type);
  915.     px_put_usq_fixed(s, x0, y0, x1, y1);
  916.     px_put_ac(s, pxaBoundingBox, pxtRectangle);
  917.     }
  918.     if (type & gx_path_type_clip) {
  919.     static const byte cr_[] = {
  920.         DA(pxaBoundingBox),
  921.         DUB(eInterior), DA(pxaClipRegion),
  922.         pxtSetClipRectangle
  923.     };
  924.  
  925.     px_put_usq_fixed(s, x0, y0, x1, y1);
  926.     PX_PUT_LIT(s, cr_);
  927.     }
  928.     return 0;
  929. }
  930.  
  931. private int
  932. pclxl_beginpath(gx_device_vector * vdev, gx_path_type_t type)
  933. {
  934.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  935.     stream *s = gdev_vector_stream(vdev);
  936.  
  937.     spputc(s, pxtNewPath);
  938.     xdev->points.type = POINTS_NONE;
  939.     xdev->points.count = 0;
  940.     return 0;
  941. }
  942.  
  943. private int
  944. pclxl_moveto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
  945.          gx_path_type_t type)
  946. {
  947.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  948.     int code = pclxl_flush_points(xdev);
  949.  
  950.     if (code < 0)
  951.     return code;
  952.     return pclxl_set_cursor(xdev,
  953.                 xdev->points.current.x = (int)x,
  954.                 xdev->points.current.y = (int)y);
  955. }
  956.  
  957. private int
  958. pclxl_lineto(gx_device_vector * vdev, floatp x0, floatp y0, floatp x, floatp y,
  959.          gx_path_type_t type)
  960. {
  961.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  962.  
  963.     if (xdev->points.type != POINTS_LINES ||
  964.     xdev->points.count >= NUM_POINTS
  965.     ) {
  966.     if (xdev->points.type != POINTS_NONE) {
  967.         int code = pclxl_flush_points(xdev);
  968.  
  969.         if (code < 0)
  970.         return code;
  971.     }
  972.     xdev->points.current.x = (int)x0;
  973.     xdev->points.current.y = (int)y0;
  974.     xdev->points.type = POINTS_LINES;
  975.     } {
  976.     gs_int_point *ppt = &xdev->points.data[xdev->points.count++];
  977.  
  978.     ppt->x = (int)x, ppt->y = (int)y;
  979.     }
  980.     return 0;
  981. }
  982.  
  983. private int
  984. pclxl_curveto(gx_device_vector * vdev, floatp x0, floatp y0,
  985.        floatp x1, floatp y1, floatp x2, floatp y2, floatp x3, floatp y3,
  986.           gx_path_type_t type)
  987. {
  988.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  989.  
  990.     if (xdev->points.type != POINTS_CURVES ||
  991.     xdev->points.count >= NUM_POINTS - 2
  992.     ) {
  993.     if (xdev->points.type != POINTS_NONE) {
  994.         int code = pclxl_flush_points(xdev);
  995.  
  996.         if (code < 0)
  997.         return code;
  998.     }
  999.     xdev->points.current.x = (int)x0;
  1000.     xdev->points.current.y = (int)y0;
  1001.     xdev->points.type = POINTS_CURVES;
  1002.     }
  1003.     {
  1004.     gs_int_point *ppt = &xdev->points.data[xdev->points.count];
  1005.  
  1006.     ppt->x = (int)x1, ppt->y = (int)y1, ++ppt;
  1007.     ppt->x = (int)x2, ppt->y = (int)y2, ++ppt;
  1008.     ppt->x = (int)x3, ppt->y = (int)y3;
  1009.     }
  1010.     xdev->points.count += 3;
  1011.     return 0;
  1012. }
  1013.  
  1014. private int
  1015. pclxl_closepath(gx_device_vector * vdev, floatp x, floatp y,
  1016.         floatp x_start, floatp y_start, gx_path_type_t type)
  1017. {
  1018.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  1019.     stream *s = gdev_vector_stream(vdev);
  1020.     int code = pclxl_flush_points(xdev);
  1021.  
  1022.     if (code < 0)
  1023.     return code;
  1024.     spputc(s, pxtCloseSubPath);
  1025.     xdev->points.current.x = (int)x_start;
  1026.     xdev->points.current.y = (int)y_start;
  1027.     return 0;
  1028. }
  1029.  
  1030. private int
  1031. pclxl_endpath(gx_device_vector * vdev, gx_path_type_t type)
  1032. {
  1033.     gx_device_pclxl *const xdev = (gx_device_pclxl *)vdev;
  1034.     stream *s = gdev_vector_stream(vdev);
  1035.     int code = pclxl_flush_points(xdev);
  1036.     gx_path_type_t rule = type & gx_path_type_rule;
  1037.  
  1038.     if (code < 0)
  1039.     return code;
  1040.     if (type & (gx_path_type_fill | gx_path_type_stroke)) {
  1041.     pclxl_set_paints(xdev, type);
  1042.     spputc(s, pxtPaintPath);
  1043.     }
  1044.     if (type & gx_path_type_clip) {
  1045.     static const byte scr_[] = {
  1046.         DUB(eInterior), DA(pxaClipRegion), pxtSetClipReplace
  1047.     };
  1048.  
  1049.     if (rule != xdev->clip_rule) {
  1050.         px_put_ub(s, (rule == gx_path_type_even_odd ? eEvenOdd :
  1051.                eNonZeroWinding));
  1052.         px_put_ac(s, pxaClipMode, pxtSetClipMode);
  1053.         xdev->clip_rule = rule;
  1054.     }
  1055.     PX_PUT_LIT(s, scr_);
  1056.     }
  1057.     return 0;
  1058. }
  1059.  
  1060. /* Vector implementation procedures */
  1061.  
  1062. private const gx_device_vector_procs pclxl_vector_procs = {
  1063.     /* Page management */
  1064.     pclxl_beginpage,
  1065.     /* Imager state */
  1066.     pclxl_setlinewidth,
  1067.     pclxl_setlinecap,
  1068.     pclxl_setlinejoin,
  1069.     pclxl_setmiterlimit,
  1070.     pclxl_setdash,
  1071.     gdev_vector_setflat,
  1072.     pclxl_setlogop,
  1073.     /* Other state */
  1074.     pclxl_setfillcolor,
  1075.     pclxl_setstrokecolor,
  1076.     /* Paths */
  1077.     gdev_vector_dopath,
  1078.     pclxl_dorect,
  1079.     pclxl_beginpath,
  1080.     pclxl_moveto,
  1081.     pclxl_lineto,
  1082.     pclxl_curveto,
  1083.     pclxl_closepath,
  1084.     pclxl_endpath
  1085. };
  1086.  
  1087. /* ---------------- Driver procedures ---------------- */
  1088.  
  1089. /* ------ Open/close/page ------ */
  1090.  
  1091. /* Open the device. */
  1092. private int
  1093. pclxl_open_device(gx_device * dev)
  1094. {
  1095.     gx_device_vector *const vdev = (gx_device_vector *)dev;
  1096.     gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
  1097.     int code;
  1098.  
  1099.     vdev->v_memory = dev->memory;
  1100. /****** WRONG ******/
  1101.     vdev->vec_procs = &pclxl_vector_procs;
  1102.     code = gdev_vector_open_file(vdev, 512);
  1103.     if (code < 0)
  1104.     return code;
  1105.     pclxl_page_init(xdev);
  1106.     px_write_file_header(vdev->strm, dev);
  1107.     xdev->media_size = pxeMediaSize_next;    /* no size selected */
  1108.     memset(&xdev->chars, 0, sizeof(xdev->chars));
  1109.     xdev->chars.next_in = xdev->chars.next_out = 2;
  1110.     return 0;
  1111. }
  1112.  
  1113. /* Wrap up ("output") a page. */
  1114. /* We only support flush = true, and we don't support num_copies != 1. */
  1115. private int
  1116. pclxl_output_page(gx_device * dev, int num_copies, int flush)
  1117. {
  1118.     gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
  1119.     stream *s;
  1120.  
  1121.     /* Note that unlike close_device, end_page must not omit blank pages. */
  1122.     if (!xdev->in_page)
  1123.     pclxl_beginpage((gx_device_vector *)dev);
  1124.     s = xdev->strm;
  1125.     spputc(s, pxtEndPage);
  1126.     sflush(s);
  1127.     pclxl_page_init(xdev);
  1128.     if (ferror(xdev->file))
  1129.     return_error(gs_error_ioerror);
  1130.     return gx_finish_output_page(dev, num_copies, flush);
  1131. }
  1132.  
  1133. /* Close the device. */
  1134. /* Note that if this is being called as a result of finalization, */
  1135. /* the stream may no longer exist. */
  1136. private int
  1137. pclxl_close_device(gx_device * dev)
  1138. {
  1139.     gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
  1140.     FILE *file = xdev->file;
  1141.  
  1142.     if (xdev->in_page)
  1143.     fputc(pxtEndPage, file);
  1144.     px_write_file_trailer(file);
  1145.     return gdev_vector_close_file((gx_device_vector *)dev);
  1146. }
  1147.  
  1148. /* ------ One-for-one images ------ */
  1149.  
  1150. private const byte eBit_values[] = {
  1151.     0, e1Bit, 0, 0, e4Bit, 0, 0, 0, e8Bit
  1152. };
  1153.  
  1154. /* Copy a monochrome bitmap. */
  1155. private int
  1156. pclxl_copy_mono(gx_device * dev, const byte * data, int data_x, int raster,
  1157.         gx_bitmap_id id, int x, int y, int w, int h,
  1158.         gx_color_index zero, gx_color_index one)
  1159. {
  1160.     gx_device_vector *const vdev = (gx_device_vector *)dev;
  1161.     gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
  1162.     int code;
  1163.     stream *s;
  1164.     gx_color_index color0 = zero, color1 = one;
  1165.     gs_logical_operation_t lop;
  1166.     byte palette[2 * 3];
  1167.     int palette_size;
  1168.     pxeColorSpace_t color_space;
  1169.  
  1170.     fit_copy(dev, data, data_x, raster, id, x, y, w, h);
  1171.     code = gdev_vector_update_clip_path(vdev, NULL);
  1172.     if (code < 0)
  1173.     return code;
  1174.     pclxl_set_cursor(xdev, x, y);
  1175.     if (id != gs_no_id && zero == gx_no_color_index &&
  1176.     one != gx_no_color_index && data_x == 0
  1177.     ) {
  1178.     gx_drawing_color dcolor;
  1179.  
  1180.     color_set_pure(&dcolor, one);
  1181.     pclxl_setfillcolor(vdev, &dcolor);
  1182.     if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
  1183.         return 0;
  1184.     }
  1185.     /*
  1186.      * The following doesn't work if we're writing white with a mask.
  1187.      * We'll fix it eventually.
  1188.      */
  1189.     if (zero == gx_no_color_index) {
  1190.     if (one == gx_no_color_index)
  1191.         return 0;
  1192.     lop = rop3_S | lop_S_transparent;
  1193.     color0 = (1 << dev->color_info.depth) - 1;
  1194.     } else if (one == gx_no_color_index) {
  1195.     lop = rop3_S | lop_S_transparent;
  1196.     color1 = (1 << dev->color_info.depth) - 1;
  1197.     } else {
  1198.     lop = rop3_S;
  1199.     }
  1200.     if (dev->color_info.num_components == 1 ||
  1201.     (RGB_IS_GRAY(color0) && RGB_IS_GRAY(color1))
  1202.     ) {
  1203.     palette[0] = (byte) color0;
  1204.     palette[1] = (byte) color1;
  1205.     palette_size = 2;
  1206.     color_space = eGray;
  1207.     } else {
  1208.     palette[0] = (byte) (color0 >> 16);
  1209.     palette[1] = (byte) (color0 >> 8);
  1210.     palette[2] = (byte) color0;
  1211.     palette[3] = (byte) (color1 >> 16);
  1212.     palette[4] = (byte) (color1 >> 8);
  1213.     palette[5] = (byte) color1;
  1214.     palette_size = 6;
  1215.     color_space = eRGB;
  1216.     }
  1217.     code = gdev_vector_update_log_op(vdev, lop);
  1218.     if (code < 0)
  1219.     return 0;
  1220.     pclxl_set_color_palette(xdev, color_space, palette, palette_size);
  1221.     s = pclxl_stream(xdev);
  1222.     {
  1223.     static const byte mi_[] = {
  1224.         DUB(e1Bit), DA(pxaColorDepth),
  1225.         DUB(eIndexedPixel), DA(pxaColorMapping)
  1226.     };
  1227.  
  1228.     PX_PUT_LIT(s, mi_);
  1229.     }
  1230.     pclxl_write_begin_image(xdev, w, h, w, h);
  1231.     pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
  1232.     pclxl_write_end_image(xdev);
  1233.     return 0;
  1234. }
  1235.  
  1236. /* Copy a color bitmap. */
  1237. private int
  1238. pclxl_copy_color(gx_device * dev,
  1239.          const byte * base, int sourcex, int raster, gx_bitmap_id id,
  1240.          int x, int y, int w, int h)
  1241. {
  1242.     gx_device_vector *const vdev = (gx_device_vector *)dev;
  1243.     gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
  1244.     stream *s;
  1245.     uint source_bit;
  1246.     int code;
  1247.  
  1248.     fit_copy(dev, base, sourcex, raster, id, x, y, w, h);
  1249.     code = gdev_vector_update_clip_path(vdev, NULL);
  1250.     if (code < 0)
  1251.     return code;
  1252.     source_bit = sourcex * dev->color_info.depth;
  1253.     if ((source_bit & 7) != 0)
  1254.     return gx_default_copy_color(dev, base, sourcex, raster, id,
  1255.                      x, y, w, h);
  1256.     gdev_vector_update_log_op(vdev, rop3_S);
  1257.     pclxl_set_cursor(xdev, x, y);
  1258.     s = pclxl_stream(xdev);
  1259.     {
  1260.     static const byte ci_[] = {
  1261.         DA(pxaColorDepth),
  1262.         DUB(eDirectPixel), DA(pxaColorMapping)
  1263.     };
  1264.  
  1265.     px_put_ub(s, eBit_values[dev->color_info.depth /
  1266.                  dev->color_info.num_components]);
  1267.     PX_PUT_LIT(s, ci_);
  1268.     }
  1269.     pclxl_write_begin_image(xdev, w, h, w, h);
  1270.     pclxl_write_image_data(xdev, base, source_bit, raster,
  1271.                w * dev->color_info.depth, 0, h);
  1272.     pclxl_write_end_image(xdev);
  1273.     return 0;
  1274. }
  1275.  
  1276. /* Fill a mask. */
  1277. private int
  1278. pclxl_fill_mask(gx_device * dev,
  1279.         const byte * data, int data_x, int raster, gx_bitmap_id id,
  1280.         int x, int y, int w, int h,
  1281.         const gx_drawing_color * pdcolor, int depth,
  1282.         gs_logical_operation_t lop, const gx_clip_path * pcpath)
  1283. {
  1284.     gx_device_vector *const vdev = (gx_device_vector *)dev;
  1285.     gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
  1286.     int code;
  1287.     stream *s;
  1288.  
  1289.     fit_copy(dev, data, data_x, raster, id, x, y, w, h);
  1290.     if ((data_x & 7) != 0 || !gx_dc_is_pure(pdcolor) || depth > 1)
  1291.     return gx_default_fill_mask(dev, data, data_x, raster, id,
  1292.                     x, y, w, h, pdcolor, depth,
  1293.                     lop, pcpath);
  1294.     code = gdev_vector_update_clip_path(vdev, pcpath);
  1295.     if (code < 0)
  1296.     return code;
  1297.     code = gdev_vector_update_fill_color(vdev, pdcolor);
  1298.     if (code < 0)
  1299.     return 0;
  1300.     pclxl_set_cursor(xdev, x, y);
  1301.     if (id != gs_no_id && data_x == 0) {
  1302.     code = gdev_vector_update_log_op(vdev, lop);
  1303.     if (code < 0)
  1304.         return 0;
  1305.     if (pclxl_copy_text_char(xdev, data, raster, id, w, h) >= 0)
  1306.         return 0;
  1307.     }
  1308.     code = gdev_vector_update_log_op(vdev,
  1309.                      lop | rop3_S | lop_S_transparent);
  1310.     if (code < 0)
  1311.     return 0;
  1312.     pclxl_set_color_palette(xdev, eGray, (const byte *)"\377\000", 2);
  1313.     s = pclxl_stream(xdev);
  1314.     {
  1315.     static const byte mi_[] = {
  1316.         DUB(e1Bit), DA(pxaColorDepth),
  1317.         DUB(eIndexedPixel), DA(pxaColorMapping)
  1318.     };
  1319.  
  1320.     PX_PUT_LIT(s, mi_);
  1321.     }
  1322.     pclxl_write_begin_image(xdev, w, h, w, h);
  1323.     pclxl_write_image_data(xdev, data, data_x, raster, w, 0, h);
  1324.     pclxl_write_end_image(xdev);
  1325.     return 0;
  1326. }
  1327.  
  1328. /* Do a RasterOp. */
  1329. private int
  1330. pclxl_strip_copy_rop(gx_device * dev, const byte * sdata, int sourcex,
  1331.              uint sraster, gx_bitmap_id id,
  1332.              const gx_color_index * scolors,
  1333.              const gx_strip_bitmap * textures,
  1334.              const gx_color_index * tcolors,
  1335.              int x, int y, int width, int height,
  1336.              int phase_x, int phase_y, gs_logical_operation_t lop)
  1337. {                /* We can't do general RasterOps yet. */
  1338. /****** WORK IN PROGRESS ******/
  1339.     return 0;
  1340. }
  1341.  
  1342. /* ------ High-level images ------ */
  1343.  
  1344. #define MAX_ROW_DATA 4000    /* arbitrary */
  1345. typedef struct pclxl_image_enum_s {
  1346.     gdev_vector_image_enum_common;
  1347.     gs_matrix mat;
  1348.     struct ir_ {
  1349.     byte *data;
  1350.     int num_rows;        /* # of allocated rows */
  1351.     int first_y;
  1352.     uint raster;
  1353.     } rows;
  1354. } pclxl_image_enum_t;
  1355. gs_private_st_suffix_add1(st_pclxl_image_enum, pclxl_image_enum_t,
  1356.               "pclxl_image_enum_t", pclxl_image_enum_enum_ptrs,
  1357.               pclxl_image_enum_reloc_ptrs, st_vector_image_enum,
  1358.               rows.data);
  1359.  
  1360. /* Start processing an image. */
  1361. private int
  1362. pclxl_begin_image(gx_device * dev,
  1363.           const gs_imager_state * pis, const gs_image_t * pim,
  1364.           gs_image_format_t format, const gs_int_rect * prect,
  1365.           const gx_drawing_color * pdcolor,
  1366.           const gx_clip_path * pcpath, gs_memory_t * mem,
  1367.           gx_image_enum_common_t ** pinfo)
  1368. {
  1369.     gx_device_vector *const vdev = (gx_device_vector *)dev;
  1370.     gx_device_pclxl *const xdev = (gx_device_pclxl *)dev;
  1371.     const gs_color_space *pcs = pim->ColorSpace;
  1372.     pclxl_image_enum_t *pie;
  1373.     byte *row_data;
  1374.     int num_rows;
  1375.     uint row_raster;
  1376.     /*
  1377.      * Following should divide by num_planes, but we only handle chunky
  1378.      * images, i.e., num_planes = 1.
  1379.      */
  1380.     int bits_per_pixel =
  1381.     (pim->ImageMask ? 1 :
  1382.      pim->BitsPerComponent * gs_color_space_num_components(pcs));
  1383.     gs_matrix mat;
  1384.     int code;
  1385.  
  1386.     /*
  1387.      * Check whether we can handle this image.  PCL XL 1.0 and 2.0 only
  1388.      * handle orthogonal transformations.
  1389.      */
  1390.     gs_matrix_invert(&pim->ImageMatrix, &mat);
  1391.     gs_matrix_multiply(&mat, &ctm_only(pis), &mat);
  1392.     /* Currently we only handle portrait transformations. */
  1393.     if (mat.xx <= 0 || mat.xy != 0 || mat.yx != 0 || mat.yy <= 0 ||
  1394.     (pim->ImageMask ?
  1395.      (!gx_dc_is_pure(pdcolor) || pim->CombineWithColor) :
  1396.      (!pclxl_can_handle_color_space(pim->ColorSpace) ||
  1397.       (bits_per_pixel != 1 && bits_per_pixel != 4 &&
  1398.        bits_per_pixel != 8))) ||
  1399.     format != gs_image_format_chunky ||
  1400.     prect
  1401.     )
  1402.     goto use_default;
  1403.     row_raster = (bits_per_pixel * pim->Width + 7) >> 3;
  1404.     num_rows = MAX_ROW_DATA / row_raster;
  1405.     if (num_rows > pim->Height)
  1406.     num_rows = pim->Height;
  1407.     if (num_rows <= 0)
  1408.     num_rows = 1;
  1409.     pie = gs_alloc_struct(mem, pclxl_image_enum_t, &st_pclxl_image_enum,
  1410.               "pclxl_begin_image");
  1411.     row_data = gs_alloc_bytes(mem, num_rows * row_raster,
  1412.                   "pclxl_begin_image(rows)");
  1413.     if (pie == 0 || row_data == 0) {
  1414.     code = gs_note_error(gs_error_VMerror);
  1415.     goto fail;
  1416.     }
  1417.     code = gdev_vector_begin_image(vdev, pis, pim, format, prect,
  1418.                    pdcolor, pcpath, mem,
  1419.                    &pclxl_image_enum_procs,
  1420.                    (gdev_vector_image_enum_t *)pie);
  1421.     if (code < 0)
  1422.     return code;
  1423.     pie->mat = mat;
  1424.     pie->rows.data = row_data;
  1425.     pie->rows.num_rows = num_rows;
  1426.     pie->rows.first_y = 0;
  1427.     pie->rows.raster = row_raster;
  1428.     *pinfo = (gx_image_enum_common_t *) pie;
  1429.     {
  1430.     gs_logical_operation_t lop = pis->log_op;
  1431.  
  1432.     if (pim->ImageMask) {
  1433.         const byte *palette = (const byte *)
  1434.         (pim->Decode[0] ? "\377\000" : "\000\377");
  1435.  
  1436.         code = gdev_vector_update_fill_color(vdev, pdcolor);
  1437.         if (code < 0)
  1438.         goto fail;
  1439.         code = gdev_vector_update_log_op
  1440.         (vdev, lop | rop3_S | lop_S_transparent);
  1441.         if (code < 0)
  1442.         goto fail;
  1443.         pclxl_set_color_palette(xdev, eGray, palette, 2);
  1444.     } else {
  1445.         int bpc = pim->BitsPerComponent;
  1446.         int num_components = pie->plane_depths[0] * pie->num_planes / bpc;
  1447.         int sample_max = (1 << bpc) - 1;
  1448.         byte palette[256 * 3];
  1449.         int i;
  1450.  
  1451.         code = gdev_vector_update_log_op
  1452.         (vdev, (pim->CombineWithColor ? lop : rop3_know_T_0(lop)));
  1453.         if (code < 0)
  1454.         goto fail;
  1455.         for (i = 0; i < 1 << bits_per_pixel; ++i) {
  1456.         gs_client_color cc;
  1457.         gx_device_color devc;
  1458.         int cv = i, j;
  1459.         gx_color_index ci;
  1460.  
  1461.         for (j = num_components - 1; j >= 0; cv >>= bpc, --j)
  1462.             cc.paint.values[j] = pim->Decode[j * 2] +
  1463.             (cv & sample_max) *
  1464.             (pim->Decode[j * 2 + 1] - pim->Decode[j * 2]) /
  1465.             sample_max;
  1466.         (*pcs->type->remap_color)
  1467.             (&cc, pcs, &devc, pis, dev, gs_color_select_source);
  1468.         if (!gx_dc_is_pure(&devc))
  1469.             return_error(gs_error_Fatal);
  1470.         ci = gx_dc_pure_color(&devc);
  1471.         if (dev->color_info.num_components == 1) {
  1472.             palette[i] = (byte)ci;
  1473.         } else {
  1474.             byte *ppal = &palette[i * 3];
  1475.  
  1476.             ppal[0] = (byte) (ci >> 16);
  1477.             ppal[1] = (byte) (ci >> 8);
  1478.             ppal[2] = (byte) ci;
  1479.         }
  1480.         }
  1481.         if (dev->color_info.num_components == 1)
  1482.         pclxl_set_color_palette(xdev, eGray, palette,
  1483.                     1 << bits_per_pixel);
  1484.         else
  1485.         pclxl_set_color_palette(xdev, eRGB, palette,
  1486.                     3 << bits_per_pixel);
  1487.     }
  1488.     }
  1489.     return 0;
  1490.  fail:
  1491.     gs_free_object(mem, row_data, "pclxl_begin_image(rows)");
  1492.     gs_free_object(mem, pie, "pclxl_begin_image");
  1493.  use_default:
  1494.     return gx_default_begin_image(dev, pis, pim, format, prect,
  1495.                   pdcolor, pcpath, mem, pinfo);
  1496. }
  1497.  
  1498. /* Write one strip of an image, from pie->rows.first_y to pie->y. */
  1499. private int
  1500. image_transform_x(const pclxl_image_enum_t *pie, int sx)
  1501. {
  1502.     return (int)((pie->mat.tx + sx * pie->mat.xx + 0.5) /
  1503.          ((const gx_device_pclxl *)pie->dev)->scale.x);
  1504. }
  1505. private int
  1506. image_transform_y(const pclxl_image_enum_t *pie, int sy)
  1507. {
  1508.     return (int)((pie->mat.ty + sy * pie->mat.yy + 0.5) /
  1509.          ((const gx_device_pclxl *)pie->dev)->scale.y);
  1510. }
  1511. private int
  1512. pclxl_image_write_rows(pclxl_image_enum_t *pie)
  1513. {
  1514.     gx_device_pclxl *const xdev = (gx_device_pclxl *)pie->dev;
  1515.     stream *s = pclxl_stream(xdev);
  1516.     int y = pie->rows.first_y;
  1517.     int h = pie->y - y;
  1518.     int xo = image_transform_x(pie, 0);
  1519.     int yo = image_transform_y(pie, y);
  1520.     int dw = image_transform_x(pie, pie->width) - xo;
  1521.     int dh = image_transform_y(pie, y + h) - yo;
  1522.     static const byte ii_[] = {
  1523.     DA(pxaColorDepth),
  1524.     DUB(eIndexedPixel), DA(pxaColorMapping)
  1525.     };
  1526.  
  1527.     if (dw <= 0 || dh <= 0)
  1528.     return 0;
  1529.     pclxl_set_cursor(xdev, xo, yo);
  1530.     px_put_ub(s, eBit_values[pie->bits_per_pixel]);
  1531.     PX_PUT_LIT(s, ii_);
  1532.     pclxl_write_begin_image(xdev, pie->width, h, dw, dh);
  1533.     pclxl_write_image_data(xdev, pie->rows.data, 0, pie->rows.raster,
  1534.                pie->rows.raster << 3, 0, h);
  1535.     pclxl_write_end_image(xdev);
  1536.     return 0;
  1537. }
  1538.  
  1539. /* Process the next piece of an image. */
  1540. private int
  1541. pclxl_image_plane_data(gx_image_enum_common_t * info,
  1542.                const gx_image_plane_t * planes, int height,
  1543.                int *rows_used)
  1544. {
  1545.     pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
  1546.     int data_bit = planes[0].data_x * info->plane_depths[0];
  1547.     int width_bits = pie->width * info->plane_depths[0];
  1548.     int i;
  1549.  
  1550.     /****** SHOULD HANDLE NON-BYTE-ALIGNED DATA ******/
  1551.     if (width_bits != pie->bits_per_row || (data_bit & 7) != 0)
  1552.     return_error(gs_error_rangecheck);
  1553.     if (height > pie->height - pie->y)
  1554.     height = pie->height - pie->y;
  1555.     for (i = 0; i < height; pie->y++, ++i) {
  1556.     if (pie->y - pie->rows.first_y == pie->rows.num_rows) {
  1557.         int code = pclxl_image_write_rows(pie);
  1558.  
  1559.         if (code < 0)
  1560.         return code;
  1561.         pie->rows.first_y = pie->y;
  1562.     }
  1563.     memcpy(pie->rows.data +
  1564.              pie->rows.raster * (pie->y - pie->rows.first_y),
  1565.            planes[0].data + planes[0].raster * i + (data_bit >> 3),
  1566.            pie->rows.raster);
  1567.     }
  1568.     *rows_used = height;
  1569.     return pie->y >= pie->height;
  1570. }
  1571.  
  1572. /* Clean up by releasing the buffers. */
  1573. private int
  1574. pclxl_image_end_image(gx_image_enum_common_t * info, bool draw_last)
  1575. {
  1576.     pclxl_image_enum_t *pie = (pclxl_image_enum_t *) info;
  1577.     int code = 0;
  1578.  
  1579.     /* Write the final strip, if any. */
  1580.     if (pie->y > pie->rows.first_y && draw_last)
  1581.     code = pclxl_image_write_rows(pie);
  1582.     gs_free_object(pie->memory, pie->rows.data, "pclxl_end_image(rows)");
  1583.     gs_free_object(pie->memory, pie, "pclxl_end_image");
  1584.     return code;
  1585. }
  1586.